package com.jmx.manager.controller;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.jmx.manager.service.JmxService;
import com.sun.management.HotSpotDiagnosticMXBean;
import com.sun.management.OperatingSystemMXBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.management.*;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import java.lang.management.*;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@RestController
public class JMXController {

    private String host = "127.0.0.1";
    private int port = 8999;
    @Autowired
    private JmxService jmxService;

    @GetMapping("getMBeansInfo")
    public Set<ObjectInstance> getMBeansInfo() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        Set<ObjectInstance> mBeans = jmxService.getMBeans(mBeanServer);
        return mBeans;
    }

    @GetMapping("getMBeanConstructorInfo")
    public MBeanConstructorInfo[] getMBeanConstructorInfo(String objectName) throws Exception {
        ObjectName on = new ObjectName(objectName);
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        return jmxService.getMBeanConstructorInfo(mBeanServer, on);
    }

    @GetMapping("getMBeanAttributeInfo")
    public JSONArray getMBeanAttributeInfo(String objectName) throws Exception {
        ObjectName on = new ObjectName(objectName);
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        MBeanAttributeInfo[] mBeanAttributeInfo = jmxService.getMBeanAttributeInfo(mBeanServer, on);
        JSONArray objects = new JSONArray();
        for (MBeanAttributeInfo mb : mBeanAttributeInfo) {
            JSONObject o = (JSONObject)JSON.toJSON(mb);
            try {
                Object value = jmxService.getMBeanAttributeValue(mBeanServer, on, mb);
                if (value instanceof CompositeDataSupport) {
                    JSONObject v = (JSONObject) JSON.toJSON(value);
                    v.put("contents", this.getCompositeDataSupportValue(value));
                    o.put("value", v);
                } else if (value instanceof CompositeData[]) {
                    JSONArray ja = new JSONArray();
                    for (Object item : (CompositeData[])value) {
                        Object compositeDataSupportValue = this.getCompositeDataSupportValue(item);
                        if (compositeDataSupportValue == null) {
                            compositeDataSupportValue = value;
                        }
                        JSONObject jo = (JSONObject) JSONObject.toJSON(item);
                        jo.put("contents", compositeDataSupportValue);
                        ja.add(jo);
                    }
                    o.put("value", ja);
                } else {
                    o.put("value", value);
                }
            }catch (Exception e){
                e.printStackTrace();
            }
            objects.add(o);
        }
        return objects;
    }

    public Object getCompositeDataSupportValue(Object value) throws Exception {
        if (value instanceof CompositeDataSupport) {
            Field contents = value.getClass().getDeclaredField("contents");
            contents.setAccessible(true);
            return contents.get(value);
        }
        return null;
    }

    @GetMapping("getMBeanOperationInfo")
    public MBeanOperationInfo[] getMBeanOperationInfo(String objectName) throws Exception {
        ObjectName on = new ObjectName(objectName);
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);

        MBeanOperationInfo[] mBeanOperationInfo = jmxService.getMBeanOperationInfo(mBeanServer, on);
        return mBeanOperationInfo;
    }

    @GetMapping("getThreadMXBean")
    public JSONObject getThreadMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        JSONObject threadMXBean = jmxService.getThreadMXBean(mBeanServer);

        return threadMXBean;
    }

    @RequestMapping("getThreadMXBeanBytes")
    public long[] getThreadMXBeanBytes(long[] ids) throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        long[] m = jmxService.getThreadMXBeanBytes(mBeanServer, ids);

        return m;
    }

    @GetMapping("dumpAllThreads")
    public ThreadInfo[] dumpAllThreads() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        ThreadInfo[] threadInfos = jmxService.getThreadMXBeanDump(mBeanServer);

        return threadInfos;
    }

    @GetMapping("getClassLoadingMXBean")
    public ClassLoadingMXBean getClassLoadingMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        ClassLoadingMXBean classLoadingMXBean = jmxService.getClassLoadingMXBean(mBeanServer);

        return classLoadingMXBean;
    }

    @GetMapping("getRuntimeMXBean")
    public RuntimeMXBean getRuntimeMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        RuntimeMXBean runtimeMXBean = jmxService.getRuntimeMXBean(mBeanServer);

        return runtimeMXBean;
    }

    @GetMapping("getOperatingSystemMXBean")
    public OperatingSystemMXBean getOperatingSystemMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        OperatingSystemMXBean operatingSystemMXBean = jmxService.getOperatingSystemMXBean(mBeanServer);

        return operatingSystemMXBean;
    }

    @GetMapping("getMemoryPoolMXBean")
    public MemoryPoolMXBean getMemoryPoolMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        MemoryPoolMXBean memoryPoolMXBean = jmxService.getMemoryPoolMXBean(mBeanServer);

        return memoryPoolMXBean;
    }

    @GetMapping("getMemoryMXBean")
    public MemoryMXBean getMemoryMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        MemoryMXBean memoryMXBean = jmxService.getMemoryMXBean(mBeanServer);

        return memoryMXBean;
    }

    @GetMapping("getHotSpotDiagnosticMXBean")
    public HotSpotDiagnosticMXBean getHotSpotDiagnosticMXBean() throws Exception {
        MBeanServerConnection mBeanServer = jmxService.getMBeanServer(host, port);
        HotSpotDiagnosticMXBean hotSpotDiagnosticMXBean = jmxService.getHotSpotDiagnosticMXBean(mBeanServer);

        return hotSpotDiagnosticMXBean;
    }

}
